package com.plian.system.service.sys.orgzation.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.plian.Tools.*;
import com.plian.system.config.exception.MyRuntimeException;
import com.plian.system.constant.sys.OrgConstant;
import com.plian.system.constant.sys.SystemConstant;
import com.plian.system.entity.sys.BaseServiceOrg;
import com.plian.system.entity.sys.ServiceOrg;
import com.plian.system.entity.sys.ServiceOrgFormType;
import com.plian.system.mapper.sys.BaseServiceOrgMapper;
import com.plian.system.mapper.sys.ServiceOrgMapper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.ListResult;
import com.plian.system.model.ObjResult;
import com.plian.system.mybatis.support.Condition;
import com.plian.system.mybatis.support.Query;
import com.plian.system.node.ForestNodeMerger;
import com.plian.system.service.sys.orgzation.IServiceOrgFormTypeService;
import com.plian.system.service.sys.orgzation.IServiceOrgService;
import com.plian.system.vo.sys.BaseServiceOrgRecordVO;
import com.plian.system.vo.sys.ServiceOrgVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.plian.system.constant.sys.OrgConstant.CHILD_ORG_CODE_START;
import static com.plian.system.constant.sys.OrgConstant.ORG_DEFAULT_DATE;


@Slf4j
@Service
@AllArgsConstructor
public class ServiceOrgServiceImpl extends ServiceImpl<ServiceOrgMapper, ServiceOrg> implements IServiceOrgService {

    private BaseServiceOrgMapper baseServiceOrgMapper;

    private IServiceOrgFormTypeService serviceOrgFormTypeService;

    @Override
    public List<ServiceOrgVO> latestTree(Long baseServiceOrgId) {
        ServiceOrg tokenOrg = getLatestOrg(TokenUtil.getTokenOrgId());
        return ForestNodeMerger.merge(getBaseMapper().getLatestTreeList(baseServiceOrgId, tokenOrg.getOrgCode()));
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public boolean submit(ServiceOrg serviceOrg) {
        if (serviceOrg.getBaseServiceOrgId() == null){
            throw new MyRuntimeException(new ObjResult("业务组织ID 为null！"));
        }
        if (StringUtil.isBlank(serviceOrg.getId()) && !"3".equals(serviceOrg.getType())){
            BaseServiceOrg baseServiceOrg = baseServiceOrgMapper.selectById(serviceOrg.getBaseServiceOrgId());
            if (baseServiceOrg.getIsMain() != null && baseServiceOrg.getIsMain() == SystemConstant.YES){
                throw new MyRuntimeException(new ObjResult("该业务组织不允许增加该类型组织！"));
            }
        }

        Date now = DateUtil.now();
        if (serviceOrg.getId() != null){
            ServiceOrg tempOrg = getById(serviceOrg.getId());
            ServiceOrg latestOrg = getOne(Wrappers.<ServiceOrg>lambdaQuery().eq(ServiceOrg::getInitialId, tempOrg.getInitialId())
                    .eq(ServiceOrg::getIsLatest, SystemConstant.YES));
            if (latestOrg == null){
                throw new MyRuntimeException(new ObjResult("该节点修改信息失败！"));
            }
            if (ObjectUtil.nullSafeEquals(latestOrg.getName(), serviceOrg.getName()) &&
                ObjectUtil.nullSafeEquals(latestOrg.getParentId(), serviceOrg.getParentId()) &&
                ObjectUtil.nullSafeEquals(latestOrg.getOrderNum(), serviceOrg.getOrderNum()) &&
                ObjectUtil.nullSafeEquals(latestOrg.getType(), serviceOrg.getType())){
                //无任何修改直接返回
                return true;
            }

            latestOrg.setIsLatest(SystemConstant.NO);
            updateById(latestOrg);
            serviceOrg.setOrgCode(latestOrg.getOrgCode());

            if (!ObjectUtil.nullSafeEquals(latestOrg.getParentId(), serviceOrg.getParentId())){
                ServiceOrg parentOrg = getOne(Wrappers.<ServiceOrg>lambdaQuery().eq(ServiceOrg::getInitialId, serviceOrg.getParentId())
                        .eq(ServiceOrg::getIsLatest, SystemConstant.YES));
                List<ServiceOrg> orgList;
                String parentCode = "";
                if (parentOrg != null){
                    orgList = list(Wrappers.<ServiceOrg>lambdaQuery()
                            .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                            .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                            .eq(ServiceOrg::getParentId, serviceOrg.getParentId()));
                    parentCode = parentOrg.getOrgCode();
                }else {
                    orgList = list(Wrappers.<ServiceOrg>lambdaQuery()
                            .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                            .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                            .eq(ServiceOrg::getParentId, OrgConstant.DEFAULT_PARENT_ID));
                }
                String oldOrgCode = serviceOrg.getOrgCode();
                serviceOrg.setOrgCode(getOrgCode(orgList, parentCode));
                changeChildOrgCode(serviceOrg, oldOrgCode, now);
            }
            serviceOrg.setVersion(latestOrg.getVersion() + 1);
            serviceOrg.setLastVersionId(latestOrg.getId());
            serviceOrg.setInitialId(latestOrg.getInitialId());
            serviceOrg.setMainVersionInitialId(latestOrg.getMainVersionInitialId());
            serviceOrg.setStatus(latestOrg.getStatus());
            serviceOrg.setTypeCode(latestOrg.getTypeCode());
            serviceOrg.setIsUnit(latestOrg.getIsUnit());
            serviceOrg.setStatus(latestOrg.getStatus());
            serviceOrg.setForGzw(latestOrg.getForGzw());
            serviceOrg.setIsMain(latestOrg.getIsMain());
            serviceOrg.setIsMonitor(latestOrg.getIsMonitor());
            serviceOrg.setId(null);
        }else {
            List<ServiceOrg> orgList;
            String parentCode = "";
            if (StringUtil.isBlank(serviceOrg.getParentId())
                    || OrgConstant.DEFAULT_PARENT_ID.equals(serviceOrg.getParentId())){
                orgList = list(Wrappers.<ServiceOrg>lambdaQuery()
                        .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                        .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                        .eq(ServiceOrg::getParentId, OrgConstant.DEFAULT_PARENT_ID));
                serviceOrg.setParentId(OrgConstant.DEFAULT_PARENT_ID);
            }else {
                ServiceOrg parentOrg = getOne(Wrappers.<ServiceOrg>lambdaQuery().eq(ServiceOrg::getInitialId, serviceOrg.getParentId())
                        .eq(ServiceOrg::getIsLatest, SystemConstant.YES));
                orgList = list(Wrappers.<ServiceOrg>lambdaQuery()
                        .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                        .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                        .eq(ServiceOrg::getParentId, serviceOrg.getParentId()));
                parentCode = parentOrg.getOrgCode();
            }
            serviceOrg.setVersion(1);
            serviceOrg.setOrgCode(getOrgCode(orgList, parentCode));
            serviceOrg.setId(UuidUtil.get32UUID());
            serviceOrg.setInitialId(serviceOrg.getId());
        }

        serviceOrg.setCreateTime(now);
        serviceOrg.setUpdateTime(now);
        serviceOrg.setEffectiveTime(now);
        serviceOrg.setIsEffective(SystemConstant.YES);
        serviceOrg.setIsLatest(SystemConstant.YES);
        return save(serviceOrg);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public boolean copyOtherServiceOrg(Long otherBaseId, Long id) {
        BaseServiceOrg baseServiceOrg = baseServiceOrgMapper.selectById(otherBaseId);
        if (baseServiceOrg == null){
            throw new MyRuntimeException(new ObjResult("获取业务组织主表信息失败！"));
        }
        List<ServiceOrg> initOrgList = list(Wrappers.<ServiceOrg>lambdaQuery()
                .eq(ServiceOrg::getBaseServiceOrgId, otherBaseId)
                .eq(ServiceOrg::getIsLatest, SystemConstant.YES));
        for (ServiceOrg serviceOrg : initOrgList){
            serviceOrg.setId(null);
            serviceOrg.setVersion(1);
            serviceOrg.setLastVersionId(null);
            serviceOrg.setBaseServiceOrgId(id);
            serviceOrg.setCreateTime(ORG_DEFAULT_DATE);
            serviceOrg.setUpdateTime(ORG_DEFAULT_DATE);
            serviceOrg.setEffectiveTime(ORG_DEFAULT_DATE);
            serviceOrg.setIsEffective(SystemConstant.YES);
        }
        saveBatch(initOrgList);
        Map<String, ServiceOrg> orgCodeMap =  initOrgList.stream().collect(Collectors.toMap(ServiceOrg::getOrgCode, serviceOrg -> serviceOrg));
        for (ServiceOrg serviceOrg : initOrgList){
            serviceOrg.setInitialId(serviceOrg.getId());
            if (OrgConstant.DEFAULT_PARENT_ID.equals(serviceOrg.getParentId())){
                continue;
            }
            String parentCode = serviceOrg.getOrgCode().substring(0, serviceOrg.getOrgCode().length() - 2);
            if (orgCodeMap.containsKey(parentCode)){
                serviceOrg.setParentId(orgCodeMap.get(parentCode).getId());
            }
        }
        return updateBatchById(initOrgList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public boolean remove(ServiceOrg serviceOrg) {
        ServiceOrg org = getById(serviceOrg.getId());
        if (org == null){
            throw new MyRuntimeException(new ObjResult("该节点不存在"));
        }
        if (CollectionUtil.isNotEmpty(list(Wrappers.<ServiceOrg>lambdaQuery()
                .eq(ServiceOrg::getParentId, serviceOrg.getInitialId())))){
            throw new MyRuntimeException(new ObjResult("该节点有下级单位，不能删除！"));
        }
        org.setIsLatest(SystemConstant.NO);
        updateById(org);
        org.setVersion(org.getVersion() + 1);
        org.setLastVersionId(org.getId());
        org.setIsDel(SystemConstant.YES + "");
        org.setId(null);
        Date now = DateUtil.now();
        org.setCreateTime(now);
        org.setUpdateTime(now);
        return save(org);
    }

    @Override
    public ListResult<BaseServiceOrgRecordVO> recordList(Long baseServiceOrgId, Query query) {
        IPage<BaseServiceOrgRecordVO> pages = getBaseMapper().recordList(Condition.getPage(query), baseServiceOrgId);
        if (CollectionUtil.isNotEmpty(pages.getRecords())){
            BaseServiceOrg baseServiceOrg = baseServiceOrgMapper.selectById(baseServiceOrgId);
            for (BaseServiceOrgRecordVO recordVO : pages.getRecords()){
                recordVO.setServiceOrgName(baseServiceOrg.getServiceOrgName());
            }
        }
        ListResult<BaseServiceOrgRecordVO> listResult = new ListResult<>(CommonCode.SUCCESS);
        listResult.setList(pages.getRecords());
        listResult.setTotal(Long.valueOf(pages.getTotal()).intValue());
        return listResult;
    }

    @Override
    public boolean changeEffectiveTime(Long baseServiceOrgId, BaseServiceOrgRecordVO baseServiceOrgRecordVO) {
        if (baseServiceOrgRecordVO.getCreateTime() == null){
            throw new MyRuntimeException(new ObjResult("创建时间为空！"));
        }
        Date minCreateDate = DateUtil.getStartOfDay(baseServiceOrgRecordVO.getCreateTime());
        Date maxCreateDate = DateUtil.getEndOfDay(baseServiceOrgRecordVO.getCreateTime());
        return update(Wrappers.<ServiceOrg>lambdaUpdate()
                .eq(ServiceOrg::getBaseServiceOrgId, baseServiceOrgId)
                .ne(ServiceOrg::getVersion, 1)
                .ge(ServiceOrg::getCreateTime, minCreateDate)
                .le(ServiceOrg::getCreateTime, maxCreateDate)
                .set(ServiceOrg::getEffectiveTime, baseServiceOrgRecordVO.getEffectiveTime())
                .set(ServiceOrg::getFailureTime, baseServiceOrgRecordVO.getFailureTime()));
    }

    @Override
    public List<ServiceOrgVO> getListByFormTypeAndTime(Integer fromType, String queryTime) {
        if (StringUtil.isBlank(queryTime)){
            queryTime = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_DATE);
        }
        return getBaseMapper().getTreeListByTime(getBaseServiceOrgIdByFormType(fromType), queryTime, null);
    }

//    @Override TODO DEL
//    public List<ServiceOrgVO> getTreeByFormTypeAndTime(Integer fromType, String queryTime) {
//        return ForestNodeMerger.merge(getListByFormTypeAndTime(fromType, queryTime));
//    }

    @Override
    public List<ServiceOrgVO> getListByFormTypeAndTime(String mainVersionInitialId, Integer fromType, String queryTime) {
        if (StringUtil.isBlank(queryTime)){
            queryTime = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_DATE);
        }
        Long baseServiceOrgId = getBaseServiceOrgIdByFormType(fromType);
        ServiceOrg serviceOrg = getBaseMapper().getOneByBaseServiceOrgIdAndTimeAndMainVersionInitialId(mainVersionInitialId, baseServiceOrgId, queryTime);
        if (serviceOrg == null){
            throw new MyRuntimeException(new ObjResult("获取单位信息失败！"));
        }

        return getBaseMapper().getTreeListByTime(baseServiceOrgId, queryTime, serviceOrg.getOrgCode());
    }

    @Override
    public List<ServiceOrgVO> getTreeByFormTypeAndTime(String mainVersionInitialId, Integer fromType, String queryTime) {
        return  ForestNodeMerger.merge(getListByFormTypeAndTime(mainVersionInitialId, fromType, queryTime));
    }

    /**
     * 根据formType获取版本id
     * @param fromType
     * @return
     */
    private Long getBaseServiceOrgIdByFormType(Integer fromType){
        ServiceOrgFormType serviceOrgFormType = serviceOrgFormTypeService
                .getOne(Wrappers.<ServiceOrgFormType>lambdaQuery().eq(ServiceOrgFormType::getFormType, fromType));
        if (serviceOrgFormType == null){
            throw new MyRuntimeException(new ObjResult("业务组织基础配置获取失败！"));
        }
        Long baseServiceOrgId = serviceOrgFormType.getBaseServiceOrgId();
        if (baseServiceOrgId == null){
            BaseServiceOrg baseServiceOrg = baseServiceOrgMapper
                    .selectOne(Wrappers.<BaseServiceOrg>lambdaQuery().eq(BaseServiceOrg::getIsMain, SystemConstant.YES));
            if (baseServiceOrg == null){
                throw new MyRuntimeException(new ObjResult("业务组织主板本获取失败！"));
            }
            baseServiceOrgId = baseServiceOrg.getId();
        }
        return baseServiceOrgId;
    }

    @Override
    public List<ServiceOrgVO> getMainOrgListByTime(String queryTime) {
        BaseServiceOrg baseServiceOrg = baseServiceOrgMapper
                .selectOne(Wrappers.<BaseServiceOrg>lambdaQuery().eq(BaseServiceOrg::getIsMain, SystemConstant.YES));
        if (baseServiceOrg == null){
            throw new MyRuntimeException(new ObjResult("业务组织主板本获取失败！"));
        }
        if (StringUtil.isBlank(queryTime)){
            queryTime = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_DATE);
        }
        return getBaseMapper().getTreeListByTime(baseServiceOrg.getId(), queryTime, null);
    }

    @Override
    public List<ServiceOrgVO> getMainOrgTreeByTime(String queryTime) {
        return ForestNodeMerger.merge(getMainOrgListByTime(queryTime));
    }

    @Override
    public List<ServiceOrgVO> getMainOrgListByTokenAndTime(String queryTime) {
        List<ServiceOrgVO> allOrgList = getMainOrgListByTime(queryTime);
        String tokenOrgId = TokenUtil.getTokenOrgId();
        Map<String, ServiceOrgVO> allOrgMap = allOrgList.stream().collect(Collectors.toMap(ServiceOrgVO::getMainVersionInitialId, orgVo -> orgVo));
        if (!allOrgMap.containsKey(tokenOrgId)){
            return Collections.emptyList();
        }
        ServiceOrgVO tokenOrg = allOrgMap.get(tokenOrgId);
        return allOrgList.stream().filter(orgVO ->
                StringUtil.isNotBlank(orgVO.getOrgCode()) && orgVO.getOrgCode().startsWith(tokenOrg.getOrgCode())).collect(Collectors.toList());
    }

    @Override
    public List<ServiceOrgVO> getMainOrgTreeByTokenAndTime(String queryTime) {
        return ForestNodeMerger.merge(getMainOrgListByTokenAndTime(queryTime));
    }

    @Override
    public List<ServiceOrg> getChildById(String orgId) {
        ServiceOrg serviceOrg = getById(orgId);
        if (serviceOrg == null){
            return Collections.emptyList();
        }
        return list(Wrappers.<ServiceOrg>lambdaQuery()
                .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                .ne(ServiceOrg::getId, orgId)
                .likeRight(ServiceOrg::getOrgCode, serviceOrg.getOrgCode()));
    }

    @Override
    public List<String> getChildIdsById(String orgId) {
        return getChildById(orgId).stream().map(ServiceOrg::getMainVersionInitialId).collect(Collectors.toList());
    }

    @Override
    public List<ServiceOrg> getChildAndOneSelfById(String orgId) {
        ServiceOrg serviceOrg = getById(orgId);
        if (serviceOrg == null){
            return Collections.emptyList();
        }
        return list(Wrappers.<ServiceOrg>lambdaQuery()
                .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                .likeRight(ServiceOrg::getOrgCode, serviceOrg.getOrgCode()));
    }

    @Override
    public List<String> getChildIdsAndOneSelfById(String orgId) {
        return getChildAndOneSelfById(orgId).stream().map(ServiceOrg::getMainVersionInitialId).collect(Collectors.toList());
    }

    @Override
    public ServiceOrg getLatestOrg(String initialId) {
        return getOne(Wrappers.<ServiceOrg>lambdaQuery()
                .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                .eq(ServiceOrg::getInitialId, initialId));
    }

    /**
     * 根据同级组织生成code
     * @param orgList
     * @param parentCode
     * @return
     */
    private String getOrgCode(List<ServiceOrg> orgList, String parentCode){
        int maxCode = 0;
        if (CollectionUtil.isEmpty(orgList)){
            return parentCode + CHILD_ORG_CODE_START;
        }
        for (ServiceOrg org : orgList){
            int tempCode = Integer.valueOf(org.getOrgCode().substring(org.getOrgCode().length() - 2));
            if (tempCode > maxCode){
                maxCode = tempCode;
            }
        }
        if (maxCode < 9){
            return parentCode + SystemConstant.ZERO + (maxCode + 1);
        }else {
            return parentCode + (maxCode + 1);
        }
    }

    /**
     * 父节点code变更修改子节点code
     */
    private void changeChildOrgCode(ServiceOrg serviceOrg, String oldOrgCode, Date now){
        List<ServiceOrg> allChildServiceOrgList = list(Wrappers.<ServiceOrg>lambdaQuery()
                .eq(ServiceOrg::getBaseServiceOrgId, serviceOrg.getBaseServiceOrgId())
                .eq(ServiceOrg::getIsLatest, SystemConstant.YES)
                .likeRight(ServiceOrg::getOrgCode, oldOrgCode));
        if (CollectionUtil.isEmpty(allChildServiceOrgList)){
            return;
        }
        List<String> childIds = new ArrayList<>();
        for (ServiceOrg childServiceOrg : allChildServiceOrgList){
            childServiceOrg.setOrgCode(childServiceOrg.getOrgCode().replaceFirst(oldOrgCode, serviceOrg.getOrgCode()));
            childIds.add(childServiceOrg.getId());
            childServiceOrg.setVersion(childServiceOrg.getVersion() + 1);
            childServiceOrg.setLastVersionId(childServiceOrg.getId());
            childServiceOrg.setCreateTime(now);
            childServiceOrg.setUpdateTime(now);
            childServiceOrg.setEffectiveTime(now);
            childServiceOrg.setIsEffective(SystemConstant.YES);
            childServiceOrg.setId(null);
        }
        update(Wrappers.<ServiceOrg>lambdaUpdate().in(ServiceOrg::getId, childIds).set(ServiceOrg::getIsLatest, SystemConstant.NO));
        saveBatch(allChildServiceOrgList);
    }

}
